
#!/usr/bin/env python
# -*- coding:utf-8 -*-

from androguard.core.bytecodes.apk import APK
from xml.dom.minidom import parseString
from madb.tools.printer import info,plus,warn

class AttackSurface(object):
    def __init__(self,apkPath):
        self.path = apkPath
        self.apk = APK(self.path)
    def parse_manifest_xml(self,component,name):
        try:
            manifrest = self.apk.get_android_manifest_axml().get_xml().decode("utf-8")
            manifrestEle = parseString(manifrest).documentElement
            if component == "activity":
                activities = manifrestEle.getElementsByTagName("activity")
                for activity in activities:
                    if activity.getAttribute("android:name") == name or activity.getAttribute("android:name").split(".")[-1] == name.split(".")[-1]:
                        if activity.getAttribute("android:exported"):
                            if activity.getAttribute("android:exported") == "true":
                                info("找到暴露的activity组件[exported:true]: " + name)
                        if activity.getAttribute("android:taskAffinity"):
                                info("找到组件的taskAffinity[任务相关性],此属性常用来进行任务栈劫持:")
                                info(name +": " + activity.getAttribute("android:taskAffinity"))
                        if activity.getAttribute("android:launchMode"):
                            if activity.getAttribute("android:launchMode") == "0":
                                info(name + " 启动模式是: standard[multiple]")
                            elif activity.getAttribute("android:launchMode") == "1":
                                info(name +" 启动模式是: singleTop")
                            elif activity.getAttribute("android:launchMode") == "2":
                                info(name +" 启动模式是: singleTask")
                            elif activity.getAttribute("android:launchMode") == "3":
                                info(name +" 启动模式是: singleInstance")
                        else:
                            #print(name + " 启动模式是: standard[multiple]")
                            pass
                        intents = activity.getElementsByTagName("intent-filter")
                        schemes = list()
                        if intents:
                            for intent in intents:
                                data = intent.getElementsByTagName("data")
                                if data:
                                    for d in data:
                                        if d.getAttribute("android:scheme"):
                                            schemes.append(d.getAttribute("android:scheme"))
                            
                            results = list(set(schemes))
                            if results:
                                info("找到用于指定数据协议的scheme")
                                for r in results:
                                    info(name + " scheme: " + r)
            elif component == "receiver":
                receivers = manifrestEle.getElementsByTagName("receiver")
                for receiver in receivers:
                    if receiver.getAttribute("android:name") == name:
                        if receiver.getAttribute("android:exported"):
                            if receiver.getAttribute("android:exported") == "true":
                                info("找到暴露的receiver组件[exported:true]: " + name)
            elif component == "provider":
                providers = manifrestEle.getElementsByTagName("provider")
                for provider in providers:
                    if provider.getAttribute("android:name") == name:
                        if provider.getAttribute("android:exported"):
                            if provider.getAttribute("android:exported") == "true":
                                info("找到暴露的provider组件[exported:true]: " + name)

            elif component == "service":
                services = manifrestEle.getElementsByTagName("service")
                for service in services:
                    if service.getAttribute("android:name") == name:
                        if service.getAttribute("android:exported"):
                            if service.getAttribute("android:exported") == "true":
                                info("找到暴露的service组件[exported:true]: " + name)
                            if service.getAttribute("android:process"):
                                info("发现service以进程形式启动: " + name)
        except Exception as e:
            info("枚举攻击面脚本出现异常!")
    
    def enum_activity_attack_surface(self):
        activities = self.apk.get_activities()
        plus("检测组件Activity的攻击面:")
        for activity in activities:
            self.parse_manifest_xml("activity", activity)
            filters = self.apk.get_intent_filters("activity", activity)
            for key, values in filters.items():
                if key == "action":
                    for value in values:
                        info(activity + "[Intent-fliter]action: " + value)
                if key == "category":
                    for value in values:
                        info(activity + "[Intent-fliter]category: " + value)
    def enum_receiver_attack_surface(self,):
        receivers = self.apk.get_receivers()
        plus("检测组件receiver的攻击面:")
        for receiver in receivers:
            self.parse_manifest_xml("receiver", receiver)
            filters = self.apk.get_intent_filters("receiver", receiver)
            for key, values in filters.items():
                if key == "action":
                    for value in values:
                        info(receiver + "[Intent-fliter]action: " + value)
                if key == "category":
                    for value in values:
                        info(receiver + "[Intent-fliter]category: " + value)
    def enum_provider_attack_surface(self,):
        providers = self.apk.get_providers()
        plus("检测组件provider的攻击面:")
        for provider in providers:
            self.parse_manifest_xml("provider", provider)
            filters = self.apk.get_intent_filters("provider", provider)
            for key, values in filters.items():
                if key == "action":
                    for value in values:
                        info(provider + "[Intent-fliter]action: " + value)
                if key == "category":
                    for value in values:
                        info(provider + "[Intent-fliter]category: " + value)

    def enum_service_attack_surface(self,):
        services = self.apk.get_services()
        plus("检测组件service的攻击面:")
        for service in services:
            self.parse_manifest_xml("service", service)
            filters = self.apk.get_intent_filters("service", services)
            for key, values in filters.items():
                if key == "action":
                    for value in values:
                        info(service + "[Intent-fliter]action: " + value)
                if key == "category":
                    for value in values:
                        info(service + "[Intent-fliter]category: " + value)